#define DEBUG_VS   // Uncomment this line to debug vertex shaders
#define DEBUG_PS   // Uncomment this line to debug pixel shaders


using System;
using System.Drawing;
using System.Xml;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using D3D = Microsoft.DirectX.Direct3D;

namespace GPU_NN
{
    /// <summary>
    /// Structure Description: The structure here is defined so that when
    ///         passing a vertex we know exactly what the form of the vertex
    ///         actually looks like
    /// 
    /// Original Structure By: Christopher Dlugolinski	Date: June 12, 2007
    /// 
    /// Edited By:										Date:
    /// Reason For Editing:
    /// </summary>
    public struct myownvertexformat
    {
        public Vector3 Pos;
        public int Color;

        public myownvertexformat(Vector3 _Pos, int _Color)
        {
            Pos = _Pos;
            Color = _Color;
        }
    }

    /// <summary>
    /// Function Description: This method sets all the default information 
    ///         for our form and how to display it.  it also sets up our
    ///         device and vertexbuffer so that there are no unset variables
    /// 
    /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
    /// 
    /// Edited By:										Date:
    /// Reason For Editing:
    /// </summary>
    public class WinForm : System.Windows.Forms.Form
    {
        /// <summary>
        /// x position of the users eye
        /// </summary>
        public int eyex = 200;
        /// <summary>
        /// y position of the users eye
        /// </summary>
        public int eyey = 200;
        /// <summary>
        /// z position of the users eye
        /// </summary>
        public int eyez = -600;
        /// <summary>
        /// Object being displayed x position
        /// </summary>
        public int objectx = 200;
        /// <summary>
        /// Object being displayed y position
        /// </summary>
        public int objecty = 200;
        /// <summary>
        /// Object being displayed z position
        /// </summary>
        public int objectz = 0;

        /// <summary>
        /// Width of the image we are to display
        /// </summary>
        public static double imagewidth = 400.00;
        /// <summary>
        /// Height of the image we are to display
        /// </summary>
        public static double imageheight = 400.00;

        /// <summary>
        /// This will hold the firing order of the nodes 
        /// </summary>
        public Node[] NetworkOrder;
        /// <summary>
        /// x value of the center of the image used for distance calculations
        /// </summary>
        public double xcenter = 0;//imagewidth / 2;
        /// <summary>
        /// y value of the center of the image used for distance calculations
        /// </summary>
        public double ycenter = 0;//imageheight / 2;

        /// <summary>
        /// Array of x vertex of the image breakdown
        /// </summary>
        public double[] x = new double[(int)imagewidth + 1];
        /// <summary>
        /// y value of the image breakdown
        /// </summary>
        public double y = 0;
        /// <summary>
        /// Array to hold the distance to center for each vertex being used
        /// </summary>
        public double[] d = new double[(int)imagewidth + 1];
        /// <summary>
        /// Random variable used to set bias
        /// </summary>
        public Random randnum = new Random();
        /// <summary>
        /// a random variable used in the NN
        /// </summary>
        public double bias = 0.0;
        /// <summary>
        /// Double scripted array used for the output of the whole images vertex
        /// </summary>
        public double[,] TotalOutput = new double[(int)imagewidth + 1, (int)imageheight + 1];
        /// <summary>
        /// used as the x subscript in the array
        /// </summary>
        public int xcount = 0;
        /// <summary>
        /// used as the y subscript in the array
        /// </summary>
        public int ycount = 0;
        /// <summary>
        /// This is the boolean to check if the NN has run its course
        /// </summary>
        public bool totaldone = false;
        /// <summary>
        /// Array to hold the number of vertices that are in the image
        /// this is in my own vertex format
        /// </summary>
        public myownvertexformat[] vertices = new myownvertexformat[160000];
        /// <summary>
        /// used to hold the values that need to be streamed into the .fx file
        /// for fast vertex processing
        /// </summary>
        public VertexDeclaration vd;
        
        /// <summary>
        /// In our DirectX app, we will first load the .fx file into an
        /// Effect object, and set the transformation matrix. So first we
        /// need an Effect object to store our effect
        /// </summary>
        public Effect effect;

        private System.ComponentModel.Container components = null;
        /// <summary>
        /// this is our one and only graphics device
        /// </summary>
        private D3D.Device device;
        /// <summary>
        /// This is used to hold information on the buffer to be output
        /// to the screen 
        /// </summary>
        private VertexBuffer vb;
        private VertexBuffer vb1;
        /// <summary>
        /// used to hold the eye position matrix
        /// </summary>
        private Vector3 CameraPos;
        /// <summary>
        /// used to hold the view matrix for displaying the image
        /// </summary>
        private Matrix matView;
        /// <summary>
        /// used to hold the matrix for the projection.  our viewable area or pyramid
        /// </summary>
        private Matrix matProjection;
        /// <summary>
        /// used for updating and checking our frame rate
        /// </summary>
        private int LastTickCount = 1;
        /// <summary>
        /// used to hold the count of frames 
        /// </summary>
        private int Frames = 0;
        /// <summary>
        /// hold the previous frame rate from the last check
        /// </summary>
        private double LastFrameRate = 0;
        /// <summary>
        /// holds the type of text that will be displayed on the form
        /// </summary>
        private D3D.Font text;
        /// <summary>
        /// the count of the nodes when read in from the XML
        /// </summary>
        public int nTotalNodes;
        /// <summary>
        /// used when cycling through the nodes array
        /// </summary>
        public int nodecount;
        /// <summary>
        /// used for debugging and seeing the output from the XML parser
        /// </summary>
        public String contents;
        /// <summary>
        /// this hold the array of nodes read in from the XML file
        /// </summary>
        public Node[] p_NetworkNodes;

        /// <summary>
        /// button used to run the NN and get an output
        /// </summary>
        private Button btnRunNN;
        /// <summary>
        /// button used to read in an XML file
        /// </summary>
        private Button btnReadXML;
        private Button btnLearn;
        /// <summary>
        /// used for displaying position on screen
        /// </summary>
        private Label label1;

        /// <summary>
        /// Function Description: This is the main form of the application it
        ///         holds all fo the information for setup this is also where
        ///         we set the bias for the Neural Network
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public WinForm()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
            //this.TransparencyKey = Color.Yellow;

            bias = .75;// randnum.NextDouble() * 2;
        }

        /// <summary>
        /// Function Description: This method initializes the device (our graphics card) and
        ///         sets our callback function for changing the size of the form 
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void InitializeDevice()
        {
            PresentParameters presentParams = new PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;
            presentParams.AutoDepthStencilFormat = DepthFormat.D16;
            presentParams.EnableAutoDepthStencil = true;

            Caps DevCaps = D3D.Manager.GetDeviceCaps(0, D3D.DeviceType.Hardware);
            D3D.DeviceType DevType = D3D.DeviceType.Reference;
            CreateFlags DevFlags = CreateFlags.SoftwareVertexProcessing;
            if ((DevCaps.VertexShaderVersion >= new Version(2, 0)) && (DevCaps.PixelShaderVersion >= new Version(2, 0)))
            {
                DevType = D3D.DeviceType.Hardware;
                if (DevCaps.DeviceCaps.SupportsHardwareTransformAndLight)
                {
                    DevFlags = CreateFlags.HardwareVertexProcessing;
                    if (DevCaps.DeviceCaps.SupportsPureDevice)
                    {
                        DevFlags |= CreateFlags.PureDevice;
                    }
                }
            }
            device = new D3D.Device(0, DevType, this, DevFlags, presentParams);
            device.DeviceReset += new EventHandler(this.HandleDeviceReset);
        }

        /// <summary>
        /// Function Description: This is code off the internet on how to handle a key 
        ///         press arrow or control if there are buttons or other controls on 
        ///         the page.  it passes control from the controls on the page to the 
        ///         main form so that it can register your key press
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.X || keyData == Keys.Z || keyData == Keys.R || keyData == Keys.L || keyData == Keys.U || keyData == Keys.D || keyData == Keys.I || keyData == Keys.O || keyData == Keys.Up || keyData == Keys.Down || keyData == Keys.Left || keyData == Keys.Right)
            {
                Form1_KeyDown(this, new KeyEventArgs(keyData));
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }
        
        /// <summary>
        /// Function Description: This is the actual handling of the arrows key press 
        ///         to either zoom in or to zoom out and move left and right to see things
        ///         it lets the user move the screen objects or the eyepoint itself
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            //Console.WriteLine(e.KeyCode.ToString());
            if (e.KeyCode == Keys.Z)
            {
                objectz = objectz + 2;
            }
            if (e.KeyCode == Keys.X)
            {
                objectz = objectz - 2;
            }
            if (e.KeyCode == Keys.R)
            {
                objectx = objectx + 2;
            }
            if (e.KeyCode == Keys.L)
            {
                objectx = objectx - 2;
            }
            if (e.KeyCode == Keys.U)
            {
                objecty = objecty + 2;
            }
            if (e.KeyCode == Keys.D)
            {
                objecty = objecty - 2;
            }
            if (e.KeyCode == Keys.Up)
            {
                // this is the zoom in
                eyey = eyey + 2;
            }
            if (e.KeyCode == Keys.Down)
            {
                eyey = eyey - 2;
            }
            if (e.KeyCode == Keys.I)
            {
                eyez = eyez + 2;
            }
            if (e.KeyCode == Keys.O)
            {
                eyez = eyez - 2;
            }
            if (e.KeyCode == Keys.Left)
            {
                eyex = eyex - 2;
            }
            if (e.KeyCode == Keys.Right)
            {
                eyex = eyex + 2;
            }
        }

        /// <summary>
        /// Function Description: this is the callback for the changing of the 
        ///         window size it restarts the drawing process
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HandleDeviceReset(object sender, EventArgs e)
        {
            FillResources();
        }

        /// <summary>
        /// Function Description: Allocation of resources for use of the GPU
        ///         vertexBuffer is the holder for all the vertices when
        ///         using the cpu only
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void AllocateResources()
        {
            vb = new VertexBuffer(typeof(myownvertexformat), 160000, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture0, Pool.Managed);
            vb1 = new VertexBuffer(typeof(myownvertexformat), 160000, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture0, Pool.Managed);
            InitializeFont();

            effect = D3D.Effect.FromFile(device, @"../../GPU.fx", null, null, ShaderFlags.None, null);
        }

        /// <summary>
        /// Function Description: This method fills in our data from the NN and 
        ///         puts it into our VertexBuffer and VertexDeclaration so we can
        ///         either push the info throught the cpu or gpu respectively.
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void FillResources()
        {
            // these vertices need to be filled with the x, and y data that is read in
            if (!totaldone)
            {
                vertices[0] = new myownvertexformat(new Vector3(2f, -2f, -2f), Color.Red.ToArgb());
                vertices[1] = new myownvertexformat(new Vector3(0f, 2f, 0f), Color.Yellow.ToArgb());
                vertices[2] = new myownvertexformat(new Vector3(-2f, -2f, 2f), Color.Green.ToArgb());
                vertices[3] = new myownvertexformat(new Vector3(-4f, 2f, 4f), Color.Red.ToArgb());

                vb1.SetData(vertices, 0, LockFlags.None);
                //vb.SetData(vertices, 0, LockFlags.None);

                SetUpCamera();
                device.RenderState.Lighting = false;
            }
            else
            {
                for(int yvalue = 0;yvalue < 400;yvalue++)
                {
                    for (int xvalue = 0; xvalue< 400; xvalue++)
                    {
                        if(-1.0 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < -.75)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.White.ToArgb());
                        else if (-.75 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < -.50)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.LightSkyBlue.ToArgb());
                        else if (-.50 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < -.25)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.LightBlue.ToArgb());
                        else if (-.25 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < 0.0)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.SkyBlue.ToArgb());
                        else if (0.0 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < .25)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.Blue.ToArgb());
                        else if (.25 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < .50)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.DarkBlue.ToArgb());
                        else if (.50 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] < .75)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.DeepSkyBlue.ToArgb());
                        else if (.75 <= TotalOutput[xvalue, yvalue] && TotalOutput[xvalue, yvalue] <= 1)
                            vertices[xvalue + (yvalue * 400)] = new myownvertexformat(new Vector3((float)xvalue, (float)yvalue, 2), Color.Black.ToArgb());                        
                    }
                }
                vb.SetData(vertices, 0, LockFlags.None);

                SetUpCamera();
                device.RenderState.Lighting = false;
            }
            VertexElement[] velements = new VertexElement[]{
                new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
                new VertexElement(0, 12, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0),
               VertexElement.VertexDeclarationEnd
                };
            vd = new VertexDeclaration(device, velements);
        }

        /// <summary>
        /// Function Description: This method just initializes the font that we use
        ///         to display our text to the form for debugging
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void InitializeFont()
        {
            System.Drawing.Font systemfont = new System.Drawing.Font("Arial", 12f, FontStyle.Regular);
            text = new D3D.Font(device, systemfont);
        }
        
        /// <summary>
        /// Function Description: This method overrides the OnPaint of the form 
        ///         that displays to our user.  it also writes whatever we want
        ///         to the screen for testing and refreshes all the controls 
        ///         for every drawing of the framebuffer that comes through
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {     
            label1.Text = "eyex= " + eyex + "  " + "eyey= " + eyey + "  " + "eyez= " + eyez +
                "\n" + "objectx= " + objectx + " " + "objecty= " + objecty + " " + "objectz= " + objectz + "\n";
            SetUpCamera();
            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
            device.BeginScene();

            device.Transform.World = Matrix.Identity;
            device.VertexFormat = CustomVertex.PositionColored.Format;
            
            // indicates which vertex stream we want to be drawn from
            device.SetStreamSource(0, vb1, 0);
            //device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

            // This sets up our device to use our vertex declaration data
            device.VertexDeclaration = vd;
            
            // this sets the technique
            effect.Technique = "Simplest";
            // This line sets the xViewProjection variable in the .fx file to dispay 3D to 2D
            effect.SetValue("xViewProjection", matView * matProjection);
            ColorValue colval1 = new ColorValue();
            //float[] colval = new float[4];
            ColorValue[] colval = new ColorValue[5];
            colval1 = ColorValue.FromColor(Color.Blue);
            colval[0] = ColorValue.FromColor(Color.Purple);// Color.Blue.ToArgb();
            colval[1] = ColorValue.FromColor(Color.Gray);// Color.Gray.ToArgb();
            colval[2] = ColorValue.FromColor(Color.Pink);//Color.Pink.ToArgb();
            colval[3] = ColorValue.FromColor(Color.Purple);//Color.Purple.ToArgb();
            colval[4] = ColorValue.FromColor(Color.Blue);//Color.Purple.ToArgb();
            effect.SetValue("arraymine", colval);
            effect.SetValue("holdcolor", colval1);

            
            // Now we need to run our points throught the .fx file
            int numpasses = effect.Begin(0);
            for (int i = 0; i < numpasses; i++)
            {
                // Starting the flow of the data through the .fx file
                effect.BeginPass(i);
                // This line needs to be altered to allow me to draw the entire picture
                device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
                // End of this particular pass
                effect.EndPass();
            }
            effect.End();

            //switches to drawing the old way through the gpu
            device.SetStreamSource(0, vb, 0);
            device.DrawPrimitives(PrimitiveType.LineList, 0, 80000);

            btnReadXML.BringToFront();
            btnRunNN.BringToFront();
            UpdateFramerate();

            device.EndScene();
            btnReadXML.Refresh();
            btnLearn.Refresh();
            btnRunNN.Refresh();
            label1.Refresh();

            device.Present();
            this.Invalidate();
        }

        /// <summary>
        /// Function Description: This method updates the frame rate that you see
        ///         in the bottom left corner of the form that comes up this is just
        ///         what comes with the tutorial that the implementation was learned
        ///         from.  it may be removed if you wish
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void UpdateFramerate()
        {
            Frames++;
            if (Math.Abs(Environment.TickCount - LastTickCount) > 1000)
            {
                LastFrameRate = (double)Frames * 1000 / Math.Abs(Environment.TickCount - LastTickCount);
                LastTickCount = Environment.TickCount;
                Frames = 0;
            }
            text.DrawText(null, string.Format("Framerate : {0:0.00} fps", LastFrameRate), new Point(10, 430), Color.Red);
        }

        /// <summary>
        /// Function Description: This method is used to set the view of the camera and the 
        ///         layout of the picture that is going to be rendered
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        private void SetUpCamera()
        {
            //CameraPos = new Vector3(200, 200, -600);
            CameraPos = new Vector3(eyex, eyey, eyez);
            matProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, 1.0f, 1.0f, 1000.0f);
            //matView = Matrix.LookAtLH(CameraPos, new Vector3(200, 200, 0), new Vector3(0, 1, 0));
            matView = Matrix.LookAtLH(CameraPos, new Vector3(objectx, objecty, objectz), new Vector3(0, 1, 0));

            device.Transform.Projection = matProjection;
            device.Transform.View = matView;

            //CameraPos = new Vector3(0, 5, 5);
            //matProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, .5f, 20f);
            //matView = Matrix.LookAtLH(CameraPos, new Vector3(0, 0, 0), new Vector3(0, 1, 0));

            //device.Transform.Projection = matProjection;
            //device.Transform.View = matView;

        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.btnRunNN = new System.Windows.Forms.Button();
            this.btnReadXML = new System.Windows.Forms.Button();
            this.label1 = new System.Windows.Forms.Label();
            this.btnLearn = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // btnRunNN
            // 
            this.btnRunNN.Enabled = false;
            this.btnRunNN.Location = new System.Drawing.Point(396, 15);
            this.btnRunNN.Name = "btnRunNN";
            this.btnRunNN.Size = new System.Drawing.Size(84, 23);
            this.btnRunNN.TabIndex = 1;
            this.btnRunNN.Text = "Run Network";
            this.btnRunNN.UseVisualStyleBackColor = true;
            this.btnRunNN.Click += new System.EventHandler(this.btnRunNN_Click);
            // 
            // btnReadXML
            // 
            this.btnReadXML.Location = new System.Drawing.Point(13, 14);
            this.btnReadXML.Name = "btnReadXML";
            this.btnReadXML.Size = new System.Drawing.Size(83, 23);
            this.btnReadXML.TabIndex = 0;
            this.btnReadXML.Text = "Read XML";
            this.btnReadXML.UseVisualStyleBackColor = true;
            this.btnReadXML.Click += new System.EventHandler(this.btnReadXML_Click);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.BackColor = System.Drawing.Color.Black;
            this.label1.ForeColor = System.Drawing.Color.Red;
            this.label1.Location = new System.Drawing.Point(268, 431);
            this.label1.MaximumSize = new System.Drawing.Size(225, 35);
            this.label1.MinimumSize = new System.Drawing.Size(225, 35);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(225, 35);
            this.label1.TabIndex = 8;
            // 
            // btnLearn
            // 
            this.btnLearn.Enabled = false;
            this.btnLearn.Location = new System.Drawing.Point(174, 14);
            this.btnLearn.Name = "btnLearn";
            this.btnLearn.Size = new System.Drawing.Size(130, 23);
            this.btnLearn.TabIndex = 9;
            this.btnLearn.Text = "Learn Network Route";
            this.btnLearn.UseVisualStyleBackColor = true;
            this.btnLearn.Click += new System.EventHandler(this.btnLearn_Click);
            // 
            // WinForm
            // 
            this.ClientSize = new System.Drawing.Size(492, 466);
            this.Controls.Add(this.btnLearn);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.btnRunNN);
            this.Controls.Add(this.btnReadXML);
            this.Name = "WinForm";
            this.Text = "Group 3 GPU-NN Picture";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        /// <summary>
        /// Function Description: This is the Main loop of the application it 
        ///         initializes then allocates then the user reads the XML creates 
        ///         the NN and then runs the NN
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        static void Main()
        {
            using (WinForm our_directx_form = new WinForm())
            {
                our_directx_form.InitializeDevice();
                our_directx_form.AllocateResources();
                //our_directx_form.ReadXML();
                //our_directx_form.RunNN();
                our_directx_form.FillResources();
                Application.Run(our_directx_form);
            }
        }

        /// <summary>
        /// Function Description: This is a function used to find the node with a certain id
        ///         then this node is returned and used elsewhere in the program
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        Node FindNode(int id)
        {
            Node node = null;
            // Need to initialize the links
            for (int i = 0; i < nTotalNodes; i++)
            {
                if (p_NetworkNodes[i].GetNodeID() == id)
                {
                    node = p_NetworkNodes[i];
                }
            }
            return node;
        }

        /// <summary>
        /// Function Description: This is the code that will set up the inputs to each of the nodes
        ///         in the NN this is just to setup a count on the number of inputs 
        ///         the node should have before being fired(executed)
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        void SetInputs()
        {
            Link link;
            ArrayList list;
            for (int i = 0; i < nTotalNodes; i++)
            {
                // This will return the linkArray
                list = p_NetworkNodes[i].GetNodeLinkList();
                // Cycle through the linkArray finding the targets of this node
                // set the targets to have another input for this node
                for (int j = 0; j < list.Count; j++)
                {
                    link = (Link)list[j];
                    // Find the Target node so that we can set it
                    for (int k = 0; k < nTotalNodes; k++)
                    {
                        if (p_NetworkNodes[k].GetNodeID() == link.GetLinkTargetID())
                        {
                            // Set the inputArray to have another input
                            p_NetworkNodes[k].m_nNumofInputs = p_NetworkNodes[k].m_nNumofInputs + 1;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Function Description: Button press to read in an XML file.  It parses looking for
        ///			only the elements that are necessary to fill in our Neural Network or the
        ///			nodes and links in our network.
        ///
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void btnReadXML_Click(object sender, EventArgs e)
        {
            // Set the status of the buttons
            btnRunNN.Enabled = false;
            btnLearn.Enabled = true;
            btnReadXML.Enabled = false;

            // String for debugging
            //String contents;

            // Xml reader to parse the xml file
            XmlReader Reader = XmlReader.Create(@"../../network.xml");

            // Read in the xml file
            while (Reader.Read())
            {
                if (Reader.NodeType == XmlNodeType.Element)
                {
                    if (Reader.Name == "links")
                    {
                        // Only Attribute is number of links
                        contents += Reader.GetAttribute(0);

                        // Create an array of the links
                        //p_NodeLinks = new cli.array<CNode^>(Convert.ToInt32(contents));
                    }
                    else if (Reader.Name == "nodes")
                    {
                        // Only Attribute is number of nodes
                        //contents = Reader.Name;
                        contents += Reader.GetAttribute(0);
                        nTotalNodes = Convert.ToInt32(Reader.GetAttribute(0));

                        // Create an array of the nodes
                        p_NetworkNodes = new Node[nTotalNodes];
                        NetworkOrder = new Node[nTotalNodes];        
                    }
                    else if (Reader.Name == "link")
                    {
                        // Need to look up this node in the array of nodes
                        Node tempNode = new Node();
                        Link link = new Link();
                        
                        // This is an element move to the attribute
                        Reader.MoveToNextAttribute();

                        // an EndElement will stop this loop through the "node"
                        while (Reader.NodeType != XmlNodeType.EndElement)
                        {
                            // whitespace is what it is called when it reads this /> 
                            // in an xml file
                            if (Reader.NodeType == XmlNodeType.Whitespace)
                            {
                                // go to next line and get attribute count for that subnode
                                Reader.Read();
                            }

                            if (Reader.NodeType == XmlNodeType.Text)
                            {
                                // This is only needed for the Activation node
                                // his xml file is poorly formatted
                                contents += "Weight=";
                                contents += Reader.Value + "\n";
                                String don;
                                don = Reader.Value;
                                double weight;
                                System.Decimal di;
                                di = Convert.ToDecimal(don);
                                weight = (double)di;
                                link.SetLinkWeight(weight);
                                //tempNode.SetNodeLinkWeight(weight, nTotalNodes);
                            }

                            if (Reader.NodeType == XmlNodeType.Element)
                            {
                                if (Reader.Name == "link")
                                {
                                    // Start of new Element go to attribute
                                    Reader.Read();
                                }
                                if (Reader.Name == "marking")
                                {
                                    // Start of new Element go to attribute
                                    //Reader.MoveToNextAttribute();
                                    // This is the marking Branch
                                    //contents += Reader.GetAttribute(Reader.Name) + " ";

                                    // Go to next attribute
                                    //Reader.MoveToNextAttribute();
                                    // This is the marking Branch ID
                                    //contents += Reader.GetAttribute(Reader.Name) + " ";

                                    // Go to Next Line
                                    Reader.Read();
                                }
                                if (Reader.Name == "source")
                                {
                                    // Start of new Element go to attribute
                                    Reader.MoveToNextAttribute();
                                    // This is the source Branch
                                    contents += Reader.GetAttribute(Reader.Name) + " ";

                                    // Go to next attribute
                                    Reader.MoveToNextAttribute();
                                    // This is the source Branch ID
                                    contents += Reader.GetAttribute(Reader.Name) + " ";

                                    tempNode = FindNode(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
                                    tempNode.SetNodeLink(link);
                                    // Go to Next Line
                                    Reader.Read();
                                }
                                if (Reader.Name == "target")
                                {
                                    // Start of new Element go to attribute
                                    Reader.MoveToNextAttribute();
                                    // This is the target Branch
                                    contents += Reader.GetAttribute(Reader.Name) + " ";

                                    // Go to next attribute
                                    Reader.MoveToNextAttribute();
                                    // This is the target Branch ID
                                    contents += Reader.GetAttribute(Reader.Name) + " ";

                                    link.SetLinkTargetID(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
                                    //tempNode.SetNodeLink(Convert.ToInt32(Reader.GetAttribute(Reader.Name)), nTotalNodes);
                                    // Go to Next Line
                                    Reader.Read();
                                }
                            }
                            // Go to next subnode in node
                            Reader.Read();
                        }
                    }
                    // This is now done sort of
                    else if (Reader.Name == "node")
                    {
                        // Create a new Node
                        p_NetworkNodes[nodecount] = new Node(nTotalNodes);//[nTotalNodes];

                        // Move to the first attribute
                        //contents = Reader.Name;
                        Reader.MoveToNextAttribute();

                        // an EndElement will stop this loop through the "node"
                        while (Reader.NodeType != XmlNodeType.EndElement)
                        {
                            // whitespace is what it is called when it reads this "/>" 
                            // in an xml file
                            if (Reader.NodeType == XmlNodeType.Whitespace)
                            {
                                // go to next line and get attribute count for that subnode
                                Reader.Read();
                            }

                            // This is only needed for the Activation node
                            // his xml file is poorly formatted
                            if (Reader.NodeType == XmlNodeType.Text)
                            {
                                contents += "Activation=" + Reader.Value + "\n";
                                p_NetworkNodes[nodecount].SetNodeFunction(Reader.Value);
                            }

                            if (Reader.NodeType == XmlNodeType.Element)
                            {
                                // Start of new Element go to attribute
                                Reader.MoveToNextAttribute();
                            }

                            // If type is an attribute see what attribute it is
                            // and save it as needed
                            if (Reader.NodeType == XmlNodeType.Attribute)
                            {
                                // Just a label go to next attribute
                                if (Reader.Name == "label")
                                {
                                   p_NetworkNodes[nodecount].SetNodeInput(Reader.GetAttribute(Reader.Name));
                                   Reader.MoveToNextAttribute();
                                }

                                // Type need this for Network save it
                                if (Reader.Name == "type")
                                {
                                    contents += Reader.GetAttribute(Reader.Name) + " ";
                                    p_NetworkNodes[nodecount].SetNodeType(Reader.GetAttribute(Reader.Name));

                                    if (Reader.GetAttribute(Reader.Name) == "in")
                                    {
                                        p_NetworkNodes[nodecount].m_nNumofInputs = p_NetworkNodes[nodecount].m_nNumofInputs + 1;
                                    }
                                }

                                // Just the Marking element go to the attribute
                                if (Reader.Name == "marking")
                                {
                                    Reader.MoveToNextAttribute();
                                }

                                // Branch attribute may be needed save to Node
                                // and move to next attribute
                                if (Reader.Name == "branch")
                                {
                                    contents += Reader.GetAttribute(Reader.Name) + " ";
                                    p_NetworkNodes[nodecount].SetNodeBranch(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
                                    Reader.MoveToNextAttribute();
                                }

                                // ID attribute needed for traversing the NN save to Node
                                // and move to next attribute
                                if (Reader.Name == "id")
                                {
                                    contents += Reader.GetAttribute(Reader.Name) + " ";
                                    p_NetworkNodes[nodecount].SetNodeID(Convert.ToInt32(Reader.GetAttribute(Reader.Name)));
                                    Reader.MoveToNextAttribute();
                                }
                            }
                            // Done with this node read the next line
                            Reader.Read();
                        }
                        // increment the node count 
                        nodecount = nodecount + 1;
                    }
                }
            }
            //MessageBox.Show(contents, "xml file", MessageBoxButtons.OK);
            Console.WriteLine(contents);
            // Need to set the inputs for all of the nodes need to cycle through
            // the nodes and set the inputs from the target info
            SetInputs();
        }

        /// <summary>
        /// Function Description: The running of the NN only available after the NN XML file has
        ///         been read in this will do all the tracing needed through the NN that was created
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRunNN_Click(object sender, EventArgs e)
        {
            btnLearn.Enabled = false;

            // I think we can change this we need to learn the network
            // route then we can save the route and run it on all the 
            // positions in the image.
            bool done = false;
            bool xdone = false;
            bool ydone = false;
            bool ddone = false;
            bool biasdone = false;
            double xposition = -1.0;
            double yposition = 1.0;

            Random newbias = new Random();
            bias = newbias.NextDouble();
            // fill the data to be worked on
            for (int loop = 0; loop < imagewidth;loop++)
            {
                //x[loop] = (double)(1.0 / imagewidth) * loop;
                x[loop] = xposition + ((2 / imagewidth) * loop); 
            }
            for (int loop = 0; loop < imagewidth + 1; loop++)
            {
                y = yposition - ((2 / imageheight) * loop);
                for (int j = 0; j < imageheight + 1; j++)
                {
                    done = false;
                    //y = (2.0 / imageheight) * j;
                    // fill the data to be worked on
                    for (int i = 0; i < imagewidth + 1; i++)
                    {
                        // Distance to center from point being manipulated by NN
                        d[i] = (double)Math.Sqrt(((x[i] - xcenter) * (x[i] - xcenter)) + ((y - ycenter) * (y - ycenter)));
                    }

                    // Find the inputs first
                    for (int k = 0; k < nodecount; k++)
                    {
                        if (p_NetworkNodes[k].GetInputName() == "x")
                        {
                            p_NetworkNodes[k].UpdateInputValue(x[j]);
                            xdone = true;
                        }
                        if (p_NetworkNodes[k].GetInputName() == "y")
                        {
                            p_NetworkNodes[k].UpdateInputValue(y);
                            ydone = true;
                        }
                        if (p_NetworkNodes[k].GetInputName() == "d")
                        {
                            p_NetworkNodes[k].UpdateInputValue(d[j]);
                            ddone = true;
                        }
                        if (p_NetworkNodes[k].GetInputName() == "bias")
                        {
                            p_NetworkNodes[k].UpdateInputValue(bias);
                            biasdone = true;
                        }
                        if (xdone && ydone && ddone && biasdone)
                        {
                            xdone = false;
                            ydone = false;
                            ddone = false;
                            biasdone = false;
                            break;
                        }
                    }
                    //////////////////////////////////////////////////
                    // Running of the NN 
                    // Loop through the nodes checking if the input is 
                    // all there and ready to go
                    //////////////////////////////////////////////////
                    while (!done)
                    {
                        for (int i = 0; i < nodecount; i++)
                        {
                            if (p_NetworkNodes[i].m_nNumofInputs == p_NetworkNodes[i].inputArray.Count && !p_NetworkNodes[i].finished)
                            {
                                // now we can run this node
                                double outputvalue = p_NetworkNodes[i].GetNodeOutput();
                                // now we need to fill in the links with output * weight
                                FillLinksForThisNode(outputvalue, p_NetworkNodes[i]);
                                // set this node to finished so i don't process it again
                                p_NetworkNodes[i].finished = true;
                                // if this is the last node then we are done
                                if (p_NetworkNodes[i].GetNodeType() == "out")
                                {
                                    TotalOutput[xcount, ycount] = outputvalue;
                                    //Console.WriteLine("Total Output ({0},{1}) = {2}", xcount, ycount, TotalOutput[xcount, ycount]);
                                    xcount = j;
                                    ycount = loop;
                                    done = true;
                                }
                            }
                        }
                    }
                    ClearInput();
                }
            }
            totaldone = true;
            FillResources();
        }

        /// <summary>
        /// Function Description: This clears all the inputs for cycling through the NN again and again
        ///         as the inputs of the image are put in
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        public void ClearInput()
        {
            //bool xdone = false;
            //bool ydone = false;
            //bool ddone = false;
            //bool biasdone = false;

            // Find the inputs first
            for (int k = 0; k < nodecount; k++)
            {
                for (int j = 0; j < p_NetworkNodes[k].inputArray.Count; j++)
                {
                    p_NetworkNodes[k].inputArray.Clear();
                }
                p_NetworkNodes[k].finished = false;
            }
        }

        /// <summary>
        /// Function Description: This function will fill the links for an input node it shows 
        ///         all of the nodes that the input node is outputting to
        /// 
        /// Original Function By: Christopher Dlugolinski	Date: June 12, 2007
        /// 
        /// Edited By:										Date:
        /// Reason For Editing:
        /// </summary>
        /// <param name="output"></param>
        /// <param name="node"></param>
        public void FillLinksForThisNode(double output, Node node)
        {
            ArrayList linklist;
            linklist = node.GetNodeLinkList();
            if (node.GetNodeType() == "out")
            {
                return;
            }
            for (int j = 0; j < linklist.Count; j++)
            {
                Link link = (Link)linklist[j];
                // Find the Target node so that we can set it
                for (int k = 0; k < nTotalNodes; k++)
                {
                    if (p_NetworkNodes[k].GetNodeID() == link.GetLinkTargetID())
                    {
                        // Set the inputArray to have another input
                        p_NetworkNodes[k].inputArray.Add(output * link.GetLinkWeight());
                    }
                }
            }
        }

        /// <summary>
        /// This will allow the user the ability to go through the NN
        /// and find the path that information shall follow for this 
        /// particular NN and store this information into an array for
        /// processing in the runNN part of the code
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLearn_Click(object sender, EventArgs e)
        {
            btnRunNN.Enabled = true;
            btnLearn.Enabled = false;
            // Set a fake data to put through the network
            double xfake = 2;
            double yfake = 1;
            double biasfake = .75;
            double dfake = Math.Sqrt((xfake * xfake) + (yfake * yfake));
            bool done = false;
            bool xdone = false;
            bool ydone = false;
            bool ddone = false;
            bool biasdone = false;
            int ordernum = 0;
            
            // Find the inputs first
            for (int k = 0; k < nodecount; k++)
            {
                if (p_NetworkNodes[k].GetInputName() == "x")
                {
                    p_NetworkNodes[k].UpdateInputValue(xfake);
                    xdone = true;
                }
                if (p_NetworkNodes[k].GetInputName() == "y")
                {
                    p_NetworkNodes[k].UpdateInputValue(yfake);
                    ydone = true;
                }
                if (p_NetworkNodes[k].GetInputName() == "d")
                {
                    p_NetworkNodes[k].UpdateInputValue(dfake);
                    ddone = true;
                }
                if (p_NetworkNodes[k].GetInputName() == "bias")
                {
                    p_NetworkNodes[k].UpdateInputValue(biasfake);
                    biasdone = true;
                }
                if (xdone && ydone && ddone && biasdone)
                {
                    xdone = false;
                    ydone = false;
                    ddone = false;
                    biasdone = false;
                    break;
                }
            }
            while (!done)
            {
                for (int i = 0; i < nodecount; i++)
                {
                    if (p_NetworkNodes[i].m_nNumofInputs == p_NetworkNodes[i].inputArray.Count && !p_NetworkNodes[i].finished)
                    {
                        NetworkOrder[ordernum] = p_NetworkNodes[i];
                        ordernum = ordernum + 1;
                        // now we can run this node
                        double outputvalue = p_NetworkNodes[i].GetNodeOutput();
                        // now we need to fill in the links with output * weight
                        FillLinksForThisNode(outputvalue, p_NetworkNodes[i]);
                        // set this node to finished so i don't process it again
                        p_NetworkNodes[i].finished = true;
                        // if this is the last node then we are done
                        if (p_NetworkNodes[i].GetNodeType() == "out")
                        {
                            //TotalOutput[xcount, ycount] = outputvalue;
                            //Console.WriteLine("Total Output ({0},{1}) = {2}", xcount, ycount, TotalOutput[xcount, ycount]);
                            //xcount = j;
                            //ycount = loop;
                            done = true;
                        }
                    }
                }
            }
            // while loop is done track should be found clear the data
            ClearInput();
        }
    }
}
